#词法类
class Lexical:
    codes = '' #代码段
    codeLen = 0 #代码段长度
    startp = 0 #开始指针
    aheadp = 0 #先行指针
    row = 0 #当前先行指针所在行数
    char = '' #字符变量，存放最新读进的源程序字符
    token = '' #字符数组，存放构成单词的字符串
    #变量声明元组
    statements = ("char", "double", "float","int")#0表示变量声明
    #关键字元组
    keywords = ("const", "continue", "default", "else", "for", "goto", "if", "return", "short", "signed", "sizeof", "static", "struct", "switch", "void", "while", "break")
    # 常量编码
    const_code = {'integer': 1, 'float': 2, 'char': 3, 'string': 4} #5表示关键字
    #标识符的分界字符表
    delimiters = (";", ",", ".", "+", "-", "*", "/", "%", "<", ">", "!", "&", "|", "^", "?", ":", "(", ")", "[", "]", "{", "}", "=")
    #数字常量的分界字符表
    const_resolver = (';', ",", "+", "-", "*", "/", "%", "<", ">", "!", "&", "|", "^", "?", ":", ")", "]","=")
    #转义字符后可接字符
    escape = ('n', 't', 'r', 'b', 'f', '\\', "\"", '\'')
    #表达式的首字符表 暂时无效expression = ('_', '.', '(', '!', '+', '-', '*', '&', '~')
    
    #符号表，存放识别出的标识符
    legend = [] 

    def __init__(self, output):
        file = open("teststr.txt", "r") #打开代码文件
        self.codes = file.read()  #读取代码文件
        file.close()
        self.output = output
                
    #将下一输入字符读入char，搜索指示器前移一个字符
    def getchar(self):
        #如果先行指针越界，返回空格
        if self.aheadp >= self.codeLen:
            self.char = ' '
        else:
            self.char = self.codes[self.aheadp]
        self.aheadp += 1

        
    #由于分界符不属于标识符，把搜索指示器回调一个字节，把char中的字符置为空白
    def retract(self):
        self.aheadp -= 1
        self.char = ''
        
    #针对TOKEN中的字符串进行查找，看其是否是保留字，是保留字给出它的编码，否则回送0（假定0不是保留字编码）
    def reserve(self):
        for state in self.statements:
            if self.token == state:
                return 0
        for key in self.keywords:
            if self.token == key:
                return 5
        return -1
    
    #把char中的字符连接到token之后
    def concat(self):
        self.token += self.char
        
    #如我们识别出的标识符不在符号表中，我们把它装入符号表
    def install(self):
        if self.token not in self.legend:
            self.legend.append(self.token)
        return self.token
            
    #只要碰到标识符后的分界符，返回TRUE
    def delimiter(self, c):
        if c in self.delimiters or c.isspace():
            return True
        return False
    
    #只要碰到常量后的分解符，返回True
    def resolver(self, c):
        if c in self.const_resolver or c.isspace():
            return True
        return False
    
    #当成功识别转义字符时更新token
    def order_detected(self, c):
        order_num = ''
        if c == 'n': 
            order_num = '\n'
        elif c == 't':
            order_num = '\t'
        elif c == 'r':
            order_num = '\r'
        elif c == 'b':
            order_num = '\b'
        elif c == 'f':
            order_num = '\f'
        else:
            order_num = c
        return order_num
    
    #检查CHAR中的字符是否为空白。若是，则调用GETCHAR直至CHAR中进入一个非空白字符
    def getbc(self):
        self.char = self.codes[self.aheadp]
        while(self.char.isspace()):
            if self.char == '\n':   #遇到回车，先行指针所在行数+1
                self.row += 1
                self.output.append('\n') #记录当前为第几行
            self.getchar() #先行指针前移
            if self.aheadp >= self.codeLen: #如果先行指针超过代码段长度，跳出循环
                break
            else:
                self.char = self.codes[self.aheadp]
    #去除数字前的0
    def removezero(self, index):
        removetoken = self.token[index:]
        for num in removetoken:
            if num == '0':
                index += 1
            else:
                break    
        return index
#词法总控制
class Fam:
    output = []
    __lex = Lexical(output)
    list_of_fams = []
    FAMNUM = 0
    def __init__(self):
        self.list_of_fams = [self.__fam1, self.__fam2, self.__fam3, self.__fam4, self.__fam5, self.__fam6, self.__fam7, self.__fam8, self.__fam9]
        self.FAMNUM = len(self.list_of_fams)
    def main(self):
        if self.__lex.codes != '': #如果程序段非空
            self.__lex.codeLen = len(self.__lex.codes) #获得代码段长度
            #尝试使用状态机分析代码段
            while(self.__lex.startp < self.__lex.codeLen): 
                self.__lex.getbc() #滤掉空格和回车
                #如果先行指针未越界,进行识别
                if self.__lex.aheadp < self.__lex.codeLen:
                    self.__lex.startp = self.__lex.aheadp #开始指针前移
                    self.__fam1()   #初始调用状态机1，若状态机1无法识别,调用下一状态机
                self.__lex.startp = self.__lex.aheadp #开始指针前移
              
    #移回先行指针（lookahead pointer）, 开始下一状态转换图，或调用出错程序,参数fam传入当前所处状态1,2,3,4,5,6...
    def __fail(self, fam):
        if fam < self.FAMNUM:
            self.__lex.token = '' #清空已读字符串
            self.__lex.aheadp = self.__lex.startp
            self.list_of_fams[fam]() #调用下一个个自动机
        else:
            raise Exception("Illegal character {0} on line {1} ".format(self.__lex.char,self.__lex.row))
            
    #给语法分析程序返回一个二元式，并清空token字符串
    def __addReturn(self, *binary):
        self.output.append(binary)
        self.__lex.token = ''       #清空已读字符串
    #第1个有穷状态自动机,识别标识符或关键字
    def __fam1(self):
        state = 0 #初始状态
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isalpha() or c == '_':
                    self.__lex.concat() #把字符链接到已读字符串之后
                    state = 1
                    continue
                else:
                    self.__fail(1) #移回先行指针，开始下一状态转换图
                    break
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isalnum(): #字母或数字
                    self.__lex.concat()
                    continue
                #c是分界符，转往终态
                elif self.__lex.delimiter(c): 
                    state = 2
                    continue
                else:
                    self.__fail(1)
                    break
            elif state == 2:
                self.__lex.retract()        #先行指针回调
                e = self.__lex.reserve()    #看其是否是保留字，是保留字给出它的编码
                if e == -1:
                    self.__addReturn('id', self.__lex.install()) #未见过的标识符加入表，返回二元组
                else:
                    self.__addReturn(e, self.__lex.token)
                break
    #第二个有穷状态自动机，识别只能单独出现的符号
    def __fam2(self):
        self.__lex.getchar()
        c = self.__lex.char
        if c == ';' or c == '{' or c == '}' or c == '(' or c == ')' or c == '[' or c == ']' or c == ',' or c == '~' or c == '?' or c == ':' :
            self.__addReturn(self.__lex.char, '_')
        elif c == '.':
            self.__lex.getchar()
            c = self.__lex.char
            if not c.isdigit():
                self.__lex.retract()        #先行指针回调
                self.__addReturn('.', '_')
            else:
                self.__fail(2)
        else:
            self.__fail(2)
    #第三个有穷状态自动机，识别最多双字符的符号
    def __fam3(self):
        self.__lex.getchar()
        c = self.__lex.char
        if c == '-':
            self.__lex.concat() #把 - 连到已读字符串之后
            self.__lex.getchar()
            c = self.__lex.char
            if c == '>' or c == '=' or c == '-':
                self.__lex.concat()
            else:
                self.__lex.retract()        #先行指针回调,并清空char
            self.__addReturn(self.__lex.token, '_')
        elif c == '+':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '+' or c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()        #先行指针回调,并清空char
            self.__addReturn(self.__lex.token, '_')
        elif c == '*' or c == '/' or c == '%' or c == '^' or c == '!' or c == '=':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()        #先行指针回调,并清空char
            self.__addReturn(self.__lex.token, '_')
        elif c == '&':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '&' or c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()        #先行指针回调,并清空char
            self.__addReturn(self.__lex.token, '_')
        elif c == '|':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '|' or c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()        #先行指针回调,并清空char
            self.__addReturn(self.__lex.token, '_')
        else:
            self.__fail(3)
    #第四个有穷状态自动机，识别最多3字符的符号
    def __fam4(self):
        self.__lex.getchar()
        c = self.__lex.char
        if c == '<':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '<':
                self.__lex.concat()
                self.__lex.getchar()
                c = self.__lex.char
                if c == '=':
                    self.__lex.concat()
                else:
                    self.__lex.retract()        #先行指针回调,并清空char
            elif c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()
            self.__addReturn(self.__lex.token, '_')
        elif c == '>':
            self.__lex.concat() 
            self.__lex.getchar()
            c = self.__lex.char
            if c == '>':
                self.__lex.concat()
                self.__lex.getchar()
                c = self.__lex.char
                if c == '=':
                    self.__lex.concat()
                else:
                    self.__lex.retract()        #先行指针回调,并清空char
            elif c == '=':
                self.__lex.concat()
            else:
                self.__lex.retract()
            self.__addReturn(self.__lex.token, '_')
        else:
            self.__fail(4)       
    #第五个有穷状态自动机，识别十整型常量
    def __fam5(self):
        state = 0
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isdigit() and c != '0':
                    state = 1
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                else:
                    self.__fail(5) #移回先行指针，开始下一状态转换图
                    break   
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isdigit():
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                elif self.__lex.resolver(c):
                    state = 2
                    continue
                else:
                    self.__fail(5) #移回先行指针，开始下一状态转换图
                    break
            elif state == 2:
                self.__lex.retract()        #先行指针回调
                self.__addReturn(self.__lex.const_code['integer'], self.__lex.token)
                break
    #第六个有穷状态自动机，识别0或八进制和16进制整型常量
    def __fam6(self):
        state = 0
        istype = 0 #0代表0,1代表16进制，2代表八进制
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char
                if c == '0':
                    state = 1
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                else:
                    self.__fail(6) #移回先行指针，开始下一状态转换图
                    break 
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char 
                if c == 'x' or c == 'X':
                    state = 2
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                elif c >= '0' and c <= '7':
                    state = 4
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                elif self.__lex.resolver(c):
                    state = 5
                    istype = 0
                    continue
                else:
                    self.__fail(6) #移回先行指针，开始下一状态转换图
                    break        
            elif state == 2:
                self.__lex.getchar()
                c = self.__lex.char 
                if (c >= 'a' and c <= 'e') or (c >= 'A' and c <= 'E') or c.isdigit():
                    state = 3
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                else:
                    self.__fail(6) #移回先行指针，开始下一状态转换图
                    break
            elif state == 3:
                self.__lex.getchar()
                c = self.__lex.char   
                if (c >= 'a' and c <= 'e') or (c >= 'A' and c <= 'E') or c.isdigit():
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                elif self.__lex.resolver(c):
                    state = 5
                    istype = 1
                    continue
                else:
                    self.__fail(6) #移回先行指针，开始下一状态转换图
                    break
            elif state == 4:
                self.__lex.getchar()
                c = self.__lex.char 
                if c >= '0' and c <= '7':
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue
                elif self.__lex.resolver(c):
                    state = 5
                    istype = 2
                    continue
                else:
                    self.__fail(6) #移回先行指针，开始下一状态转换图
                    break
            elif state == 5:
                self.__lex.retract()        #先行指针回调
                if istype == 0:
                    self.__addReturn(self.__lex.const_code['integer'], '0')
                elif istype == 1:
                    index = self.__lex.removezero(2)
                    self.__addReturn(self.__lex.const_code['integer'], self.__lex.token[index:].lower() + 'h')
                else:
                    index = self.__lex.removezero(1)
                    self.__addReturn(self.__lex.const_code['integer'], self.__lex.token[index:].lower() + 'o')
                break
    #第七个有穷状态自动机，识别浮点数 测试样例 .80, .2e10, 9., 2e2, 9.e2, 9.9e2非法2e
    def __fam7(self):
        state = 0
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char     
                if c.isdigit():
                    state = 1
                    self.__lex.concat() #把字符链接到已读字符串之后
                    continue 
                elif c == '.':
                    state = 5
                    self.__lex.concat() 
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char   
                if c.isdigit():   
                    self.__lex.concat()
                    continue
                elif c == '.':
                    state = 2
                    self.__lex.concat()
                    continue
                elif c == 'e' or c == 'E':
                    state = 6
                    self.__lex.concat()
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 2 or state == 3:
                self.__lex.getchar()
                c = self.__lex.char  
                if c.isdigit():
                    state = 3
                    self.__lex.concat() 
                    continue
                elif c == 'f' or c == 'F':
                    state = 4
                    continue
                elif c == 'e' or c == 'E':
                    state = 6
                    self.__lex.concat()
                    continue
                elif self.__lex.resolver(c):
                    state = 9
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 4:
                self.__lex.getchar()
                c = self.__lex.char 
                if self.__lex.resolver(c):
                    state = 9
                    continue
                else:
                    self.__fail(7) 
                    break               
            elif state == 5:
                self.__lex.getchar()
                c = self.__lex.char 
                if c.isdigit():
                    state = 3
                    self.__lex.concat()
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 6:
                self.__lex.getchar()
                c = self.__lex.char 
                if c == '+' or c == '-':
                    state = 7
                    if c == '-': self.__lex.concat()
                    continue
                if c.isdigit():
                    state = 8
                    self.__lex.concat()
                    continue
                else:
                    self.__fail(7) 
                    break 
            elif state == 7:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isdigit():
                    state = 8
                    self.__lex.concat()
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 8:
                self.__lex.getchar()
                c = self.__lex.char
                if c.isdigit():
                    self.__lex.concat()
                    continue      
                elif self.__lex.resolver(c):
                    state = 9
                    continue
                else:
                    self.__fail(7) 
                    break
            elif state == 9:
                self.__lex.retract()        #先行指针回调
                self.__lex.token = self.__lex.token.lower()  
                #解析带指数小数
                if 'e' in self.__lex.token:
                    # 求e之前的值
                    position = self.__lex.token.find('e')
                    sumvalue = float(self.__lex.token[0:position])
                    #求e之后的值
                    if '-' in self.__lex.token:
                        position += 2
                        indexmark = int(self.__lex.token[position:])
                        while indexmark > 0:
                            sumvalue /= 10
                            indexmark -= 1
                    else:
                        indexmark = int(self.__lex.token[position+1:])
                        while indexmark > 0:
                            sumvalue *= 10
                            indexmark -= 1
                else:
                    sumvalue = float(self.__lex.token)
                self.__addReturn(self.__lex.const_code['float'], sumvalue)
                break 
    #第八个有穷状态自动机，识别字符       不支持  \后跟八进制或十六进制,可以读到最后一个字符   '\''; 'a' 'abc ' '\\a'                   
    def __fam8(self):
        state = 0
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char  
                if c == '\'':
                    state = 1
                    continue
                else:
                    self.__fail(8)
                    break
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char
                if c != '\'' and c != '\\' and c != '\n':
                    state = 2
                    self.__lex.token = c
                    continue
                elif c == '\\':
                    state = 3
                    continue
                else:
                    self.__fail(8)
                    break  
            elif state == 2:
                self.__lex.getchar()
                c = self.__lex.char
                if c != '\'' and c != '\\' and c != '\n':
                    self.__lex.token = c
                    continue
                elif c == '\\':
                    state = 3
                    continue      
                elif c == '\'':
                    state = 4
                    continue
                else:
                    self.__fail(8)
                    break                     
            elif state == 3:
                self.__lex.getchar()
                c = self.__lex.char
                if c in self.__lex.escape:
                    state = 2
                    self.__lex.token = self.__lex.order_detected(c)
                    continue
                else:
                    self.__fail(8)
                    break                   
            elif state == 4:
                self.__addReturn(self.__lex.const_code['char'], self.__lex.token)
                break
    #第九个有穷状态自动机，识别字符串 支持各种换行符，换行符跟空格跟回车，换行符跟回车，换行符跟其他字符无效
    def __fam9(self):
        state = 0
        space = '' #暂存空格
        while(True):
            if state == 0:
                self.__lex.getchar()
                c = self.__lex.char
                if c == "\"":
                    state = 1
                    continue
                else:
                    self.__fail(9)
                    break
            elif state == 1:
                self.__lex.getchar()
                c = self.__lex.char
                if c == "\"":
                    state = 4
                    continue
                elif c == '\\':
                    state = 2
                    continue
                elif c != "\n" :
                    self.__lex.concat()
                    continue
                else:
                    self.__fail(9)
                    break      
            elif state == 2:
                self.__lex.getchar()
                c = self.__lex.char
                if c == ' ':
                    state = 3
                    space += ' '
                    continue
                else:
                    state = 1 #遇到回车视为换行符
                    if c in self.__lex.escape:
                        self.__lex.token += self.__lex.order_detected(c)
                        continue
                    elif c != '\n':
                        self.__lex.concat()
                        continue
                    else:
                        continue
            elif state == 3:
                self.__lex.getchar()
                c = self.__lex.char
                if c == ' ':
                    space += ' '
                    continue
                elif c == '\\':
                    state = 2
                    self.__lex.token += space
                    space = ''
                    continue
                elif c == "\"":
                    state = 4
                    self.__lex.token += space
                    space = ''
                    continue
                else:
                    state = 1
                    if c == '\n':
                        space = ''
                        continue
                    else:
                        self.__lex.token += space
                        self.__lex.concat()
                        space = ''
                        continue
            elif state == 4:
                self.__addReturn(self.__lex.const_code['string'], self.__lex.token)
                break        
        
fam = Fam()
fam.main()
print(fam.output)
        
